﻿Imports System
Imports System.Collections
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization
Imports ICSharpCode.SharpZipLib.Zip
Imports unRar

Public Class Comic
    Implements IDisposable

    Private _pages As ComicPages

    Private path As String
    Public TempFolder As String
    Private _fileList As New List(Of String)
    Private actualIndex As Integer = -1
    Private disposedValue As Boolean = False        ' To detect redundant calls
    Public readMePath As String = String.Empty

    Public ReadOnly Property ComicPages() As ComicPages
        Get
            If _pages Is Nothing Then _pages = New ComicPages
            Return _pages
        End Get
    End Property

    Public Sub New()
        '  Do Nothing 
    End Sub

    Public Sub New(ByVal filePath As String)
        readMePath = String.Empty
        If IO.File.Exists(filePath) Then
            Me.actualIndex = -1
            Me.path = filePath
            Dim str As String = My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData
            Dim fileName As String = IO.Path.GetFileNameWithoutExtension(Me.path)
            Dim ext As String = IO.Path.GetExtension(Me.path)
            TempFolder = str & "/archives/" & fileName

            Dim bGoUnzip As Boolean = False
            Dim bGoUnRar As Boolean = False
            Dim bGoPdf As Boolean = False

            ext = Replace(ext, ".", "")

            ' We ASSUME that the a file is named correctly (especially on the extension. 
            '   but if there is either no extension, or an extension that we do not
            '   recognize, then we look at the various file signatures to see if it is
            '   supported file type.    
            Select Case LCase(Trim(ext))
                Case "cbz", "zip", "gzip"
                    bGoUnzip = True
                Case "rar", "cbr"
                    bGoUnRar = True
                Case "pdf"
                    bGoPdf = True
                Case Else
                    If FileChecker.CheckSignature(filePath, 7, "52-61-72-21-1A-07-00") Then bGoUnRar = True : Exit Select ' RAR checking 
                    If FileChecker.CheckSignature(filePath, 3, "1F-8B-08") Then bGoUnzip = True : Exit Select ' gzip checking 
                    If FileChecker.CheckSignature(filePath, 4, "50-4B-03-04") Then bGoUnzip = True : Exit Select ' PK-Zip Checking 
            End Select ' Case LCase(Trim(ext)) 

            If bGoUnzip Then unZip()
            If bGoUnRar Then unrar()
            If bGoPdf Then unPdf()
            If Not bGoUnzip AndAlso Not bGoUnRar AndAlso Not bGoPdf Then Throw New ArgumentException("Invalid File Format")

        ElseIf IO.Directory.Exists(filePath) Then
        Else
            Throw New FileNotFoundException()
        End If
    End Sub


    Private Sub LoadFileNames()
       
    End Sub

    Public Sub LoadFilesFromSubFolders(ByVal dirPath As String, ByRef fileList As List(Of String))
        For Each fn As String In Directory.GetFiles(dirPath)
            Dim ext As String = Replace(IO.Path.GetExtension(fn), ".", "")
            Select Case LCase(Trim(ext))
                Case "jpg", "jpeg", "gif", "bmp", "png"
                    fileList.Add(fn)
                Case "txt", "rtf"
                    readMePath = fn
                Case "xml"
                    'comicInfoFileName = fn
            End Select
        Next

        For Each dn As String In Directory.GetDirectories(dirPath)
            LoadFilesFromSubFolders(dn, fileList)
        Next ' Each dn As String In Directory.GetDirectories(dirPath) 
    End Sub ' LoadFilesFromSubFolders 

    Private Sub unpdf()
        If Not IO.Directory.Exists(TempFolder) Then IO.Directory.CreateDirectory(TempFolder)
        Dim pdfDoc As PdfSharp.Pdf.PdfDocument = PdfSharp.Pdf.IO.PdfReader.Open(Me.path)
        Dim counter As Integer = 1
        For Each Page As PdfSharp.Pdf.PdfPage In pdfDoc.Pages
            Dim resources As PdfSharp.Pdf.PdfDictionary = Page.Elements.GetDictionary("/Resources")
            If Not resources Is Nothing Then
                Dim xObjects As PdfSharp.Pdf.PdfDictionary = resources.Elements.GetDictionary("/XObject")
                If Not xObjects Is Nothing Then
                    Dim items As ICollection(Of PdfSharp.Pdf.PdfItem) = xObjects.Elements.Values
                    For Each pdfItem As PdfSharp.Pdf.PdfItem In items
                        Dim reference As PdfSharp.Pdf.Advanced.PdfReference = CType(pdfItem, PdfSharp.Pdf.Advanced.PdfReference)
                        If Not reference Is Nothing Then
                            Dim xObject As PdfSharp.Pdf.PdfDictionary = CType(reference.Value, PdfSharp.Pdf.PdfDictionary)
                            ' Ensure the Object is an external Object and an image 
                            If Not xObject Is Nothing AndAlso String.Compare(xObject.Elements.GetString("/Subtype"), "/Image") = 0 Then
                                ExportImage(xObject, counter)
                            End If ' Not xObject Is Nothing 
                        End If ' Not reference Is Nothing 
                    Next ' pdfItem In items
                End If ' Not xObjects Is Nothing 
            End If ' Not resources Is Nothing 
        Next
    End Sub

    Private Sub ExportImage(ByVal image As PdfSharp.Pdf.PdfDictionary, ByRef counter As Integer)
        Dim filter As String = image.Elements.GetName("/Filter")
        Select Case filter
            Case "/DCTDecode"
                ExportJpegFromPdf(image, counter)
            Case "/FlateDecode"
            Case Else
                ' Do Nothing 
        End Select
    End Sub

    Private Sub ExportJpegFromPdf(ByVal image As PdfSharp.Pdf.PdfDictionary, ByRef counter As Integer)
        counter += 1
        Dim stream As Byte() = image.Stream.Value
        Dim fName As String = Me.TempFolder & "/" & String.Format("page{0}.jpg", counter.ToString("0000"))
        Dim fs As New FileStream(fName, FileMode.Create, FileAccess.Write)
        Dim bw As New BinaryWriter(fs)
        bw.Write(stream)
        bw.Flush()
        bw.Close()
        fs.Close()
        fs.Dispose()
        bw = Nothing
        fs = Nothing
    End Sub
    Private Sub ExportPngFromPdf(ByVal image As PdfSharp.Pdf.PdfDictionary, ByRef counter As Integer)
        ' TO BE IMPLEMENTED 

        '        int width = image.Elements.GetInteger(PdfImage.Keys.Width);
        '04.  int height = image.Elements.GetInteger(PdfImage.Keys.Height);
        '05.  int bitsPerComponent = image.Elements.GetInteger(PdfImage.Keys.BitsPerComponent);
        '06.  
        '07.  // TODO: You can put the code here that converts vom PDF internal image format to a Windows bitmap
        '08.  // and use GDI+ to save it in PNG format.
        '09.  // It is the work of a day or two for the most important formats. Take a look at the file
        '10.  // PdfSharp.Pdf.Advanced/PdfImage.cs to see how we create the PDF image formats.
        '11.  // We don't need that feature at the moment and therefore will not implement it.
        '12.  // If you write the code for exporting images I would be pleased to publish it in a future release
        '13.  // of PDFsharp.

    End Sub


    Private Sub unrar()
        If Not IO.Directory.Exists(TempFolder) Then IO.Directory.CreateDirectory(TempFolder)
        Dim d As New Decompressor(Me.path)
        Dim b As Boolean = d.UnPackAll(Me.TempFolder)
        If Not b Then
            Throw New Exception("Rar Failed To Decompress")
        End If
    End Sub

    Private Sub unZip()
        If Not IO.Directory.Exists(TempFolder) Then IO.Directory.CreateDirectory(TempFolder)
        Dim s As New ZipInputStream(File.OpenRead(path))

        Dim theEntry As ZipEntry = s.GetNextEntry
        While Not theEntry Is Nothing
            Dim fileName As String = IO.Path.GetFileName(theEntry.Name)

            If Not fileName Is String.Empty AndAlso Not IO.File.Exists(TempFolder & "/" & fileName) Then
                Dim streamWriter As FileStream
                streamWriter = File.Create(TempFolder & "/" & fileName)
                Dim size As Integer = 2048
                Dim abyData(2048) As Byte
                While True
                    size = s.Read(abyData, 0, abyData.Length)
                    If size > 0 Then
                        streamWriter.Write(abyData, 0, size)
                    Else ' size > 0 
                        Exit While
                    End If ' size > 0 
                End While
                streamWriter.Flush()
                streamWriter.Close()
                streamWriter.Dispose()
            End If

            theEntry = s.GetNextEntry
        End While ' Not theEntry Is Nothing 		
    End Sub

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: free other state (managed objects).
            End If

            If IO.Directory.Exists(TempFolder) Then
                For Each fn As String In IO.Directory.GetFiles(TempFolder)
                    Try
                        IO.File.Delete(fn)
                    Catch ex As Exception
                    End Try
                Next
                Try
                    IO.Directory.Delete(TempFolder, True)
                Catch ex As Exception
                End Try

            End If
            ' TODO: free your own state (unmanaged objects).
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

#Region " IDisposable Support "
    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class
